package com.snpic.appaw.module.insure.service.s3;

import cn.hutool.core.util.StrUtil;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.HttpMethod;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.snpic.appaw.module.insure.service.s3.bo.S3Connect;
import com.snpic.appaw.module.insure.service.s3.bo.FileEntityBO;
import com.snpic.appaw.module.insure.util.s3.ImageWatermarkUtils;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @author JiJun
 * @date 2025/9/13 13:29
 * @修改时间 2025/9/13 13:29
 * @description
 */
@Service
@Slf4j
@Validated
public class AmazonS3ObjectServiceImpl implements AmazonS3ObjectService {
	@Resource
	private ResourceLoader resourceLoader;

	@Resource
	private AmazonS3 s3Client;

	/**
	 * 上传MultipartFile到S3
	 * 重载
	 * @param bucketName
	 * @param key           文件名字
	 * @param multipartFile
	 * @return
	 * @throws IOException FontFormatException
	 */
// 新增方法重载（无水印参数）
	@Override
	public PutObjectResult uploadMultipartFileToS3(String bucketName, String key, MultipartFile multipartFile) throws IOException, FontFormatException {
		return uploadMultipartFileToS3(bucketName, key, multipartFile, null, null);
	}

	/**
	 * 上传MultipartFile到S3
	 * 重载
	 * @param bucketName
	 * @param key           文件名字
	 * @param multipartFile
	 * @return
	 * @throws IOException FontFormatException
	 */
	@Override
	public PutObjectResult uploadMultipartFileToS3(String bucketName, String key, MultipartFile multipartFile,
																								 String waterMark, String colorstring) throws IOException , FontFormatException {

		ObjectMetadata metadata = new ObjectMetadata();
		metadata.setContentType(multipartFile.getContentType());
		metadata.addUserMetadata("Use", "CClient");


    InputStream inputStream = null;
    if (StrUtil.isAllNotEmpty(waterMark, colorstring)) {
        // 将水印处理后的流转换为字节数组以获取准确长度
        byte[] watermarkedBytes = ImageWatermarkUtils.toByteArray(
            addWaterMark(multipartFile, 30, waterMark, colorstring)
        );
        metadata.setContentLength(watermarkedBytes.length);
        inputStream = new ByteArrayInputStream(watermarkedBytes);
    } else {
        // 原始文件保持原长度设置
        metadata.setContentLength(multipartFile.getSize());
        inputStream = multipartFile.getInputStream();
    }

    PutObjectRequest putRequest = new PutObjectRequest(bucketName, key, inputStream, metadata);
    return s3Client.putObject(putRequest);

	}

	/**
	 * 单个删除对象（文件）
	 *
	 * @param bucketName
	 * @param Keys
	 */
	@Override
	public void deleteObject(String bucketName, String Keys) {
		try {
			s3Client.deleteObject(bucketName, Keys);
		} catch (AmazonServiceException e) {
			// 捕获 AWS 服务端异常（如权限错误、桶不存在等）
			log.error("S3服务端错误：删除文件失败，桶名={}，文件名={}", bucketName, Keys, e);
			throw e; // 重新抛出，让调用方处理（如返回错误响应）
		} catch (AmazonClientException e) {
			// 捕获客户端异常（如网络超时、连接失败等）
			log.error("客户端错误：删除文件失败，桶名={}，文件名={}", bucketName, Keys, e);
			throw e; // 重新抛出，确保调用方感知
		}
	}

	/**
	 * 创建文件下载(预览)地址
	 *
	 * @param bucketName
	 * @param objectKey
	 * @return 文件下载地址url
	 * @throws IOException
	 */
	@Override
	@Cacheable(value = "s3PresignedUrls#3000s", key = "#bucketName + ':' + #objectKey", unless = "#result == null")
	public String makeURL(String bucketName, String objectKey) {
		System.out.println("桶名称:" + bucketName);
		URL url = null;
		try {
			// 设置URL有效时间为1h
			java.util.Date expiration = new java.util.Date();
			long expTimeMillis = expiration.getTime();
			expTimeMillis += 1000 * 60 * 60;
			expiration.setTime(expTimeMillis);
			// 生成URL
			System.out.println("Generating pre-signed URL.");
			GeneratePresignedUrlRequest generatePresignedUrlRequest =
				new GeneratePresignedUrlRequest(bucketName, objectKey)
					.withMethod(HttpMethod.GET)
					.withExpiration(expiration);
			url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
			System.out.println("Pre-Signed URL: " + url.toString());
		} catch (AmazonServiceException e) {
			e.printStackTrace();
		} catch (SdkClientException e) {
			e.printStackTrace();
		}
		return url.toString();
	}


	/**
	 * 通过filePath方法,将本地文件夹文件,上传到对象存储
	 *
	 * @param bucketName
	 * @param key
	 * @param filePath
	 * @param s3client
	 * @return
	 */
	@Override
	public PutObjectResult PutObject(String bucketName, String key, String filePath, AmazonS3 s3client) {
		log.info("上传桶名称:" + bucketName + "通过filePath方法,将本地文件夹文件,上传到对象存储");
		File file = new File(filePath);
		log.info("文件路径filePath:" + filePath);
		PutObjectResult putResult = null;//创建用户自定义元数据
		ObjectMetadata metadata = new ObjectMetadata();
		metadata.addUserMetadata("Use", "CClient");
		//创建上传文件请求（PutObjectRequest）
		PutObjectRequest putRequest = new PutObjectRequest(bucketName, key, file);
		putRequest.setMetadata(metadata);
		//调用AmazonS3.putObject上传文件
		putResult = s3client.putObject(putRequest);

		return putResult;
	}

	/**
	 * 先从url下载文件,再上传到S3
	 *
	 * @param file
	 * @param s3client
	 * @return
	 * @throws IOException
	 * @throws AmazonServiceException
	 */
	@Override
	public PutObjectResult PutObjectRequest(FileEntityBO file, AmazonS3 s3client) throws IOException, AmazonServiceException {
		String url = file.getUrl();//中通天鸿下载录音的url
		String key = file.getKey();//上传文件名称
		String bucketName = file.getBucketName();
		boolean ismark = false;//默认是不加要加水印的
		Boolean setsize = file.getSetsize() == null ? true : file.getSetsize();//默认是要设置 setReadLimit大小的,其它情况考虑url问题
//		System.out.println("setsize:" + setsize);
		if (file.getWatermark() != null) {
			ismark = file.getWatermark().isIsmark();//判断是否加水印使用
		}
		log.info("上传桶名称:" + bucketName + "通过url 方法,请求网络文件,上传到对象存储");
		log.info("上传文件名称:" + key + "  下载文件URL录音:" + url);
		log.info("加水印:" + ismark + "  是否设置文件大小:" + setsize);
		//初始化上传文件流
		PutObjectResult putResult = null;
		//创建用户自定义元数据
		ObjectMetadata metadata = new ObjectMetadata();
		metadata.addUserMetadata("Use", "CClient");
		InputStream inStream = null;
		HttpURLConnection conn = null;
		try {
			URL httpUrl = new URL(url);
			conn = (HttpURLConnection) httpUrl.openConnection();
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(5 * 1000);
			if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
				inStream = conn.getInputStream();//输入流包含了从网络下载的文件内容数据
			}

			if (ismark) {//判断是否要加水印
				int fontsize = file.getWatermark().getFontsize();//字体大小
				String watermark = file.getWatermark().getWatermark();//水印内容
				String colorstring = file.getWatermark().getColorstring();//水印颜色
				Color color = Color.decode(colorstring);
				log.info("开始执行加水印-----水印内容:" + watermark + " 水印字体大小fontsize:" + fontsize + " 水印颜色color:" + color);
				//存在windows/Linux服务器上的相对路径的文件夹
				String path = System.getProperty("user.dir");// E:\idea_code\springboot\AmazonS3springboot\target
				log.info(path);
				File file1 = new File(path, "/font/msyh.ttf");///E:\idea_code\springboot\AmazonS3springboot\target/font/msyh.ttf
				if (!file1.getParentFile().exists()) {
					//判断文件夹是否存在存在不做任何操作，不存在则新建
					file1.getParentFile().mkdirs();
					ClassPathResource classPathResource = new ClassPathResource("font/msyh.ttf");
					InputStream inputStream = classPathResource.getInputStream();
					//将流复制到相对路径内
					Files.copy(inputStream, Paths.get(path, "/font/msyh.ttf"));
					inputStream.close();
				}
				File filefont = new File(path, "/font/msyh.ttf");
				Font font = Font.createFont(Font.TRUETYPE_FONT, filefont).deriveFont(Font.PLAIN, fontsize);
				log.info("通过本地资源文件读取字体:" + String.valueOf(font));
				inStream = ImageWatermarkUtils.markWithContent(inStream, font, color, watermark);
			}

			log.info("inStream.toString():" + inStream.toString());
			log.info("conn.getResponseCode():" + conn.getResponseCode());
			int contentLength = conn.getContentLength();
			log.info("conn.getContentLength()文件长度:" + contentLength);
			PutObjectRequest putRequest = new PutObjectRequest(bucketName, key, inStream, metadata);

			if (setsize) {//如果 url 参数为定义长度，则不设置长度,如:图片不设置   录音是设置长度的
				metadata.setContentLength(contentLength);
				putRequest.getRequestClientOptions().setReadLimit(contentLength);// 设置上传文件大写 47.68MB  否则会报错
				log.info("执行了设置文件大小");
			}
			//不设置0 报错如:  No content length specified for stream data.  Stream contents will be buffered in memory and could result in out of memory errors.
			//Connect client = new Connect();
			log.info("创建S3客户端", s3client.toString());
			putResult = s3client.putObject(putRequest);
		} catch (IOException exception) {
			log.info("IOException exception: " + exception.toString());
			log.info("IOException exception:{} :", exception);
		} catch (AmazonServiceException ase) {
			log.info("Caught an AmazonServiceException when put object of \"" + key + "\".");
			log.info("Error Message: " + ase.getMessage());
			log.info("HTTP Status Code: " + ase.getStatusCode());
			log.info("AWS Error Code: " + ase.getErrorCode());
			log.info("Error Type: " + ase.getErrorType());
			log.info("Request ID: " + ase.getRequestId());
			System.exit(1);
		} catch (FontFormatException e) {
			e.printStackTrace();
		} finally {
			if (inStream != null)
				inStream.close();
			if (conn != null)
				conn.disconnect();
		}
		return putResult;
	}

	/**
	 * 将字符串内容转换为文件并上传到S3存储
	 *
	 * @param bucketName
	 * @param key        上传到S3的文件名称
	 * @param body       要上传的字符串内容
	 * @param s3client
	 * @return
	 * @throws IOException
	 */
	@Override
	public PutObjectResult PutObjectRequestBody(String bucketName, String key, String body, AmazonS3 s3client) throws IOException {
		//初始化上传文件流
		InputStream inputStream = null;
		PutObjectResult putResult = null;
		//字符串转换为字节输入流
		inputStream = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
		//计算字符串的字节长度用于设置内容长度
		int contentLength = body.getBytes(StandardCharsets.UTF_8).length;
		log.info("字符串文件长度:" + contentLength);
		ObjectMetadata metadata = new ObjectMetadata();
		metadata.addUserMetadata("Use", "CClient");
		metadata.setContentLength(contentLength);
		try {
			//创建上传文件请求（PutObjectRequest）
			PutObjectRequest putRequest = new PutObjectRequest(bucketName, key, inputStream, metadata);
			S3Connect client = new S3Connect();
			System.out.println(s3client);
			putResult = s3client.putObject(putRequest);
		} catch (AmazonServiceException ase) {
			log.info("Caught an AmazonServiceException when put object of \"" + key + "\".");
			log.info("Error Message: " + ase.getMessage());
			log.info("HTTP Status Code: " + ase.getStatusCode());
			log.info("AWS Error Code: " + ase.getErrorCode());
			log.info("Error Type: " + ase.getErrorType());
			log.info("Request ID: " + ase.getRequestId());
			System.exit(1);
		}
		return putResult;
	}

	/**
	 *
	 * @param file
	 * @param fontsize
	 * @param watermark
	 * @param colorstring #FF0000（红色）、#00FF00（绿色）、#0000FF（蓝色）
	 * @return
	 * @throws IOException
	 * @throws FontFormatException
	 */
	public InputStream addWaterMark(MultipartFile file, int fontsize, String watermark, String colorstring) throws IOException, FontFormatException {
		Color color = Color.decode(colorstring);
		log.info("开始执行加水印-----水印内容:" + watermark + " 水印字体大小fontsize:" + fontsize + " 水印颜色color:" + color);
		//当打包为jar运行时，user.dir指向jar文件所在目录（取决于启动位置）
		String path = System.getProperty("user.dir");
		log.info(path);
		File fileFontLocal = new File(path, "/font/msyh.ttf");///E:\idea_code\springboot\AmazonS3springboot\target/font/msyh.ttf
		if (!fileFontLocal.getParentFile().exists()) {
			//判断文件夹是否存在存在不做任何操作，不存在则新建
			fileFontLocal.getParentFile().mkdirs();
			ClassPathResource classPathResource = new ClassPathResource("font/msyh.ttf");
			InputStream inputStream = classPathResource.getInputStream();
			//将字体文件(inputStream)从classpath复制到应用运行时目录
			Files.copy(inputStream, Paths.get(path, "font", "msyh.ttf"));
			inputStream.close();
		}
		Font font = Font.createFont(Font.TRUETYPE_FONT, fileFontLocal).deriveFont(Font.PLAIN, fontsize);
		log.info("通过本地资源文件读取字体:" + String.valueOf(font));
		InputStream inputStream = file.getInputStream();
		inputStream = ImageWatermarkUtils.markWithContent(inputStream, font, color, watermark);
		return inputStream;
	}


}
